import Vue from "vue";

const eventMap = {}; // 通过事件名，获取哪些组件要被调用
const parentMap = {}; // 通过_uid ，获取该组件向上的链路
const vmEventMap = {}; // 通过 _uid 获取改组件绑定了哪些事件
const globalRE = /^global:/; // 全局事件，事件响应全部；
const dispatchRE = /^dispatch:/; // 派发事件，事件沿着父链冒泡；
const broadcastRE = /^broadcast:/; // 广播事件，事件向下传导给所有的后代。
const closestRE = /^closest(?:\[([\w\W]*)\])?:([\w\W]*)$/; // 父链冒泡到指定层级，再向下传导给所有后代
const on = Vue.prototype.$on;
const emit = Vue.prototype.$emit;
const resultCache = {}; // 返回值缓存
const getParents = function (vm, arr) {
    if (!vm || !vm.$parent) {
        return arr || [];
    }
    arr = arr || [];
    arr.push(vm.$parent);
    return getParents(vm.$parent, arr);
};

// 监听事件
Vue.prototype.$on = function (eventName, fn) {
    const vm = this;
    if (!fn) {
        // 没有函数
    } else if (Array.isArray(eventName)) {
        eventName.forEach((item) => vm.$on(item, fn));
    } else {
        // 全局事件监听
        (vmEventMap[vm._uid] || (vmEventMap[vm._uid] = [])).push(eventName);
        (eventMap[eventName] || (eventMap[eventName] = [])).push(vm);
        parentMap[vm._uid] = getParents(vm);
        // on.call(vm, eventName, fn);
        on.call(vm, eventName, (...args) => {
            const id = vm._uid + "-" + eventName;
            const res = fn.call(vm, ...args);
            if (resultCache[id]) {
                resultCache[id].cb = res;
            }
            // 这个返回值不能是Promise，要不会有问题
            // return res;
        });
    }
    return vm;
};

// // 触发事件
// Vue.prototype.$emit = function (eventName, ...args) {

// 	const vm = this;
// 	if (globalRE.test(eventName)) {
// 		// 全局事件，事件响应全部；
// 		var name = eventName;
// 		(eventMap[name] || []).forEach(item => emit.apply(item, [name, ...args]));

// 	} else if(dispatchRE.test(eventName)){
// 		// 派发事件，事件沿着父链冒泡（包括自身）；
// 		var name = eventName;
// 		var parents = getParents(vm);
// 		(eventMap[name] || []).forEach(function(item){
// 			parents.indexOf(item) >= 0 && emit.apply(item, [name, ...args]);
// 		});

// 	} else if(broadcastRE.test(eventName)){
// 		// 广播事件，事件向下传导给所有的后代（包括自身）。
// 		var name = eventName;
// 		(eventMap[name] || []).forEach(function(item){
// 			(parentMap[item._uid] || []).indexOf(vm) >= 0 && emit.apply(item, [name, ...args]);
// 		});

// 	} else if(closestRE.test(eventName)){
// 		// 父链冒泡到指定层级(包括自身)，再向下传导给所有后代
// 		var match = eventName.match(closestRE) || [];
// 		var vkey = match[1] || ''; // vm 的 name 或 _uid;
// 		var name = eventName; // 事件名称
// 		var parent = getParents(vm).filter(function(vm){return vm.$options.name == vkey || vm._uid == vkey})[0] || vm;
// 		(eventMap[name] || []).forEach(function(item){
// 			(parentMap[item._uid] || []).indexOf(parent) >= 0 && emit.apply(item, [name, ...args]);
// 		});

// 	} else {
// 		emit.apply(vm, [eventName, ...args]);
// 	}
// 	return vm;
// }

// 触发事件
Vue.prototype.$emit = function (eventName, ...args) {
    const vm = this;
    const list = eventMap[eventName] || [];
    const callback = [];

    if (globalRE.test(eventName)) {
        // 全局事件，事件响应全部；
        callback.push(...list);
    } else if (dispatchRE.test(eventName)) {
        // 派发事件，事件沿着父链冒泡（包括自身）；
        const parents = getParents(vm);
        list.map((item) => parents.indexOf(item) >= 0 && callback.push(item));
    } else if (broadcastRE.test(eventName)) {
        // 广播事件，事件向下传导给所有的后代（包括自身）。
        list.map((item) => {
            if ((parentMap[item._uid] || []).indexOf(vm) >= 0) {
                callback.push(item);
            }
        });
    } else if (closestRE.test(eventName)) {
        // 父链冒泡到指定层级(包括自身)，再向下传导给所有后代
        const match = eventName.match(closestRE) || [];
        const vkey = match[1] || ""; // vm 的 name 或 _uid;
        const parents = getParents(vm).filter(
            (vm) => vm.$options.name == vkey || vm._uid == vkey
        );
        const parent = parents[0] || vm;

        list.map((item) => {
            if ((parentMap[item._uid] || []).indexOf(parent) >= 0) {
                callback.push(item);
            }
        });
    } else {
        // cbs.push(vm);
        callback.push(vm);
    }

    // 缓存
    callback.map((vm) => {
        resultCache[vm._uid + "-" + eventName] = {
            name: eventName,
            cb: null,
        };
    });

    // 执行
    callback.map((vm) => emit.apply(vm, [eventName, ...args]));

    // 返回结果
    return Promise.all(
        callback.map((vm) => {
            const id = vm._uid + "-" + eventName;
            if (resultCache[id]) {
                const cb = resultCache[id].cb;
                delete resultCache[id];
                return cb;
            } else {
                return false;
            }
        })
    ).then((res) => {
        const isFalse = res.filter((i) => typeof i == "boolean" && !i);
        if (isFalse.length > 0) {
            // 阻止了回调
            return Promise.reject();
        } else {
            return Promise.resolve();
        }
    });
    // return vm;
};

// 销毁监听
Vue.mixin({
    beforeDestroy() {
        const vm = this;
        (vmEventMap[vm._uid] || []).forEach((name) => {
            const index = eventMap[name].findIndex(
                (item) => item._uid === vm._uid
            );
            if (index >= 0) {
                (eventMap[name] || []).splice(index, 1);
                eventMap[name].length == 0 && delete eventMap[name];
            }
        });
        delete vmEventMap[vm._uid];
        delete parentMap[vm._uid];
    },
});
